
import SqlUtil from "../../Storage/SqlUtil";
import { ExtendsLoad } from "../CCExtends";

/**扩展原型组件 */
@ExtendsLoad(Number)
export class NumberBaseExtends {
    /**
      * 返回value是否在 [min, max] 区间内
      * @param min 最小  
      * @param max 最大
      * @param value 比较值
      * @param includeEdge 是否包含边界值min和max，默认包含
      */
    static inRange(min: number, max: number, value: number, includeEdge: boolean = true) {
        return includeEdge ? value >= min && value <= max : value > min && value < max;
    }


    /**
     * 获取区间[min, max)的整数，传入1个参数则区间为[0, min)
     * @param min 最小  
     * @param max 最大
     * @example
     *  randInt(1); =>  [0, 1)
     *  randInt(0.5); =>  [0, 0.5)
     */
    static randInt(min: number, max: number = undefined) {
        if (max === undefined) {
            max = min;
            min = 0;
        }
        min = Math.ceil(min);
        max = Math.floor(max);
        return Math.floor(Math.random() * (max - min)) + min;
    }

    /**
     * 获取区间[min, max)的浮点数，传入1个参数则区间为[0, min)
     * @param min 最小  
     * @param max 最大 
     * @example
     *  randFloat(1); =>  [0, 1)
     *  randFloat(0.5); =>  [0, 0.5)
     */
    static randFloat(min: number, max: number = undefined) {
        if (max === undefined) {
            max = min;
            min = 0;
        }
        return Math.random() * (max - min) + min;
    }
}
/**扩展组件实例方法 */
@ExtendsLoad(Number.prototype)
export class NumberExtends {
    /**
     * 存储当前的数值
     * @param saveStr 要存储的key
     * @param elmName 数值对应元素的名字(注意不要重复)
     */
    static saveNum(saveStr: string, elmName: string) {
        let num = this as any as number;
        let isSave = SqlUtil.setItem(saveStr, num);
        if (isSave)
            SqlUtil._setOriginalName(saveStr + '_numElmName', elmName);
        else
            console.log(`存储OriginalName失败,key:${saveStr}`);
        return isSave;
    }

    /**
     * 加载存储的数值到指定目标
     * @param target 要加载的目标（数值所在的对象）
     * @param saveStr 要加载的key
     * @param def 默认值
     */
    static reloadNum(target: any, saveStr: string, def = 0) {
        try {
            let name = SqlUtil._getOriginalName(saveStr + '_numElmName');
            if (name != null) {
                if (target && target[name] != null) {
                    target[name] = SqlUtil.getItem(saveStr, def);
                    return true;
                } else
                    console.warn(`要加载的数值目标不存在或者未创建`);
            } else
                console.warn(`要加载的数值目标 _numElmName 不存在`);
            return false;
        } catch (error) {
            return false;
        }
    }

    /**
     * 转换到指定位数
     * @param fractionDigits 位数
     * @returns 
     */
    static toNum(fractionDigits?: number) {
        let num = this as any as number;
        return Number(num.toFixed(fractionDigits));
    }

    /**
    * 根据指定格式解析数值
    * @param value 值
    * @param delFormat 格式
    * @returns 数值
    * @example
    *  组件实际使用 后面跟数字表示限制参数
    *  {{0:sep}}将数字按分号显示   100000-> 100,000 
    *  {{0:per2}} 将取值0~1 变成 1~100,可以指定修饰的小数位数  
    *  {{0:int}} 将取值变成整数 
    *  {{0:fix2}}数值转换为小数
    *  {{0:kmbt2}}将数字缩短显示为KMBT单位 
    *  {{0:limit3}}字符串长度限制 
    *  使用{{1:int}} 表示替换组件绑定的路径中第一个的数据模型 并限制为int整数
    */
    static dealValue(delFormat: string): string {
        let value = this as any as number | string;
        if (delFormat === ``) return value as string;
        delFormat = delFormat.toLowerCase().trim();//不区分大小
        let match_func = delFormat.match(/^[a-z|A-Z]+/gi);//匹配到 format 中的 函数名
        let match_num = delFormat.match(/\d+$/gi);   //匹配到 format 中的参数
        let func = match_func ? match_func[0] : ``;
        let num = match_num ? parseInt(match_num[0]) : 0;
        let res: number | string = ``;

        /**
         * 压缩当前大数字
         * @param lang 语言
         * @param fixed 预留位数
         * @returns 
         */
        let converThousand = (value: number, lang: 'zh' | 'k' = 'k', fixed: number = 2) => {
            let units: [string[], number[]] = {
                'zh': [
                    ['', '千', '万', '亿', '兆', '京'],
                    [new Decimal('1000'), new Decimal('10000'), new Decimal('100000000'), new Decimal('1000000000000'), new Decimal('10000000000000000')]
                ],
                'k': [
                    ['', 'K', 'W', 'M', 'G', 'T'],
                    [new Decimal('1000'), new Decimal('10000'), new Decimal('1000000'), new Decimal('1000000000'), new Decimal('1000000000000')]
                ],
            }[lang] as any;
            let compressUnit = (v: number, count: number[], unit: string[], fixNum: number = 2) => {
                let res = v.toFixed(0);
                let index = 0;
                for (; index < count.length; index++) {
                    if (v < count[index]) {
                        if (index == 0)
                            res = v.toFixed(fixNum);
                        else
                            res = (v / count[index - 1]).toFixed(fixNum);
                        break;
                    }
                }
                return res + unit[index];
            }
            switch (lang) {
                case `zh`:
                    return compressUnit(value, units[1], units[0], fixed);
                case `k`:
                    return compressUnit(value, units[1], units[0], fixed);
                default:
                    break;
            }
        }

        if (typeof value.valueOf() == `number`) {
            let v = value.valueOf() as number;
            switch (func) {
                /** [value:int] 将取值变成整数 */
                case `int`: res = Math.round(v); break;
                /** [value:fix]数值转换为小数*/
                case `fix`: res = v.toFixed(num); break;
                /** [value:kmbt]将数字缩短显示为KMBT单位  */
                case `kmbt`: res = converThousand(v, 'k', num); break;
                /** [value:per] 将取值0~1 变成 1~100,可以指定修饰的小数位数 */
                case `per`: res = Math.round(v * 100).toFixed(num); break;
                /**[value:sep]将数字按分号显示 100000-> 100,000 */
                case `sep`: res = Math.round(v).toString().replace(new RegExp(`(\\d)(?=(\\d{ 3}) + $)`, `ig`), "$1,"); break;
                default: break;
            }
        } else {
            let s = value.valueOf() as string;
            switch (func) {
                /** [value:limit]字符串长度限制 */
                case `limit`: res = s.substring(0, num); break;
                default: break;
            }
            // res = value;
        }
        return res as string;
    }
}